﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SocialFront.Core.Repository.EF;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Data.Entity;
using SocialStoreFront.Domain.Concrete;

namespace SocialFront.Tests
{
    [TestClass]
    public class PerfTesting
    {

        public static int numberOfTimes = 100;
        public class Result
        {
            public string Description { get; set; }
            public List<decimal> Results { get; set; }
            public decimal Average
            {
                get { return Results.Average(); }
            }
            public decimal Min
            {
                get { return Results.Min(); }
            }
            public decimal Max
            {
                get { return Results.Max(); }
            }
            public decimal First
            {
                get { return Results.First(); }
            }
            public decimal Last
            {
                get { return Results.Last(); }
            }
            public decimal AverageWithoutFirstAndLast { get { return Results.Skip(1).Take(numberOfTimes - 2).Average(); } }
            public decimal AverageWithoutMinAndMax { get { return Results.OrderBy( c=>c).Skip(1).Take(numberOfTimes - 2).Average(); } }
            public override string ToString()
            {
                return string.Format("Description={0} ,  First={1} ,  Last={2} ,  Min={3} ,  Max={4},  Avg={5} ,  AvgwoFirstLast={6} ,  AvgwoMinMax={7}"
                    , Description, First, Last, Min, Max, Average, AverageWithoutMinAndMax, AverageWithoutFirstAndLast);
            }
            public Result()
            {
                Results = new List<decimal>();
            }
        }

        [TestMethod]
        public void Test()
        {
            //Build out the db
            System.Data.Entity.Database.SetInitializer(new TestDataInitializer());
            var ctx = new SocialFrontDataContext("SocialFront");
            ctx.Database.Delete();
            ctx.Database.Create();
            ctx.Database.Initialize(true);

            //Flex the db, build out some statistics
            using (var dbCtx = GetDbContext())
            {
                dbCtx.Configuration.ProxyCreationEnabled = true;
                dbCtx.Configuration.LazyLoadingEnabled = true;

                var db = dbCtx.Set<Order>().OrderBy(c => c.Id).Take(100);

                foreach (var o in db.ToList())
                {
                    var a = o.Customer;
                    var b = o.Products;
                    var c = dbCtx.Set<Customer>().Where(x => x.Id == a.Id).FirstOrDefault();
                    if (b != null && b.Count > 0)
                    {
                        var id = b.First().Id;
                        var d = dbCtx.Set<Product>().Where(x => x.Id == id).FirstOrDefault();
                    }
                }





                var ids = db.Select(c => c.Id).ToList();
                var results = new List<Result>();

                results.Add(TestObjectCtxSetWithAllOn(ids));
                results.Add(TestDbSetWithAllOn(ids));

                results.Add(TestDbSetWithAllOff(ids));
                results.Add(TestObjectCtxSetWithAllOff(ids));

                results.Add(TestDbSetWithProxiesOnly(ids));
                results.Add(TestObjectCtxSetWithProxiesOnly(ids));

                foreach (var result in results.OrderBy(c => c.AverageWithoutMinAndMax))
                {
                    Debug.WriteLine(result.ToString());
                }


            }
        }


        private Result TestObjectCtxSetWithProxiesOnly(List<int> ids)
        {
            var result = new Result() { Description = "ObjectSet Proxies On and Lazy Loading Off" };
            for (int i = 0; i < numberOfTimes; i++)
            {
                foreach (var id in ids)
                {
                    var sw = new System.Diagnostics.Stopwatch();
                    sw.Start();
                    using (var ctx = GetObjectContext())
                    {
                        ctx.ContextOptions.LazyLoadingEnabled = false;
                        ctx.ContextOptions.ProxyCreationEnabled = true;

                        var order = ctx.CreateObjectSet<Order>().Where(x => x.Id == id)
                                                            .Include("Customer")
                            .Include("Products")

                            .FirstOrDefault();
                        var a = order.Customer;
                        var b = order.Products;

                    }
                    sw.Stop();
                    result.Results.Add(sw.ElapsedMilliseconds);
                }
            }
            return result;
        }

        private Result TestObjectCtxSetWithAllOn(List<int> ids)
        {
            var result = new Result() { Description = "ObjectSet Proxies and Lazy Loading On" };
            for (int i = 0; i < numberOfTimes; i++)
            {
                foreach (var id in ids)
                {
                    var sw = new System.Diagnostics.Stopwatch();
                    sw.Start();
                    using (var ctx = GetObjectContext())
                    {
                        ctx.ContextOptions.LazyLoadingEnabled = true;
                        ctx.ContextOptions.ProxyCreationEnabled = true;

                        var order = ctx.CreateObjectSet<Order>().Where(x => x.Id == id)
                            .FirstOrDefault();
                        var a = order.Customer;
                        var b = order.Products;

                    }
                    sw.Stop();
                    result.Results.Add(sw.ElapsedMilliseconds);
                }
            }
            return result;
        }

        private Result TestObjectCtxSetWithAllOff(List<int> ids)
        {
            var result = new Result() { Description = "ObjectSet Proxies and Lazy Loading Off" };
            for (int i = 0; i < numberOfTimes; i++)
            {
                foreach (var id in ids)
                {
                    var sw = new System.Diagnostics.Stopwatch();
                    sw.Start();
                    using (var ctx = GetObjectContext())
                    {
                        ctx.ContextOptions.LazyLoadingEnabled = false;
                        ctx.ContextOptions.ProxyCreationEnabled = false;

                        var order = ctx.CreateObjectSet<Order>().Where(x => x.Id == id)
                            .Include("Customer")
                            .Include("Products")
                            .FirstOrDefault();
                        var a = order.Customer;
                        var b = order.Products;

                    }
                    sw.Stop();
                    result.Results.Add(sw.ElapsedMilliseconds);
                }
            }
            return result;
        }


        private Result TestDbSetWithAllOff(List<int> ids)
        {
            var result = new Result() { Description = "DbSet Proxies and Lazy Loading Off" };
            for (int i = 0; i < numberOfTimes; i++)
            {
                foreach (var id in ids)
                {
                    var sw = new System.Diagnostics.Stopwatch();
                    sw.Start();
                    using (var ctx = GetDbContext())
                    {
                        ctx.Configuration.ProxyCreationEnabled = false;
                        ctx.Configuration.LazyLoadingEnabled = false;

                        var order = ctx.Set<Order>().Where(x => x.Id == id)
                            .Include("Customer")
                            .Include("Products")
                            .FirstOrDefault();
                        var a = order.Customer;
                        var b = order.Products;

                    }
                    sw.Stop();
                    result.Results.Add(sw.ElapsedMilliseconds);
                }
            }
            return result;
        }

        private Result TestDbSetWithProxiesOnly(List<int> ids)
        {
            var result = new Result() { Description = "DbSet Proxies On and Lazy Loading Off" };
            for (int i = 0; i < numberOfTimes; i++)
            {
                foreach (var id in ids)
                {
                    var sw = new System.Diagnostics.Stopwatch();
                    sw.Start();
                    using (var ctx = GetDbContext())
                    {
                        ctx.Configuration.ProxyCreationEnabled = false;
                        ctx.Configuration.LazyLoadingEnabled = false;

                        var order = ctx.Set<Order>().Where(x => x.Id == id)
                            .Include("Customer")
                            .Include("Products")
                            .FirstOrDefault();
                        var a = order.Customer;
                        var b = order.Products;

                    }
                    sw.Stop();
                    result.Results.Add(sw.ElapsedMilliseconds);
                }
            }
            return result;
        }


        private Result TestDbSetWithAllOn(List<int> ids)
        {
            var result = new Result() { Description = "DbSet Proxies and Lazy Loading" };
            for (int i = 0; i < numberOfTimes; i++)
            {
                foreach (var id in ids)
                {
                    var sw = new System.Diagnostics.Stopwatch();
                    sw.Start();
                    using (var ctx = GetDbContext())
                    {
                        ctx.Configuration.ProxyCreationEnabled = true;
                        ctx.Configuration.LazyLoadingEnabled = true;

                        var order = ctx.Set<Order>().Where(x => x.Id == id).FirstOrDefault();
                        var a = order.Customer;
                        var b = order.Products;

                    }
                    sw.Stop();
                    result.Results.Add(sw.ElapsedMilliseconds);
                }
            }
            return result;
        }


        private ObjectContext GetObjectContext()
        {
            var uow = new EFUnitOfWork();
            var oCtx = ((IObjectContextAdapter)uow.DataContext).ObjectContext;
            return oCtx;

        }
        private DbContext GetDbContext()
        {
            var uow = new EFUnitOfWork();
            return uow.DataContext;
        }
    }
}
